package icasue.tools.sqlhelper.core;

import icasue.reflect.handles.predicate.SureOF;
import icasue.tools.sqlhelper.core.providers.BaseSqlProvider;
import icasue.tools.sqlhelper.core.providers.FieldRowsSqlProvider;
import icasue.tools.sqlhelper.common.FieldsTouch;
import icasue.reflect.annotations.NotNull;
import icasue.tools.sqlhelper.core.Consult;
import icasue.tools.sqlhelper.core.Insert;
import icasue.tools.sqlhelper.core.Update;
import icasue.tools.sqlhelper.core.Query;
import icasue.tools.sqlhelper.core.Delete;
import icasue.tools.sqlhelper.core.Save;
import icasue.tools.sqlhelper.core.Count;
import icasue.tools.sqlhelper.core.FieldRows;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;

/**
 * @Author: Qiao Hang
 * @CreateDate: 2021/9/26 下午5:24
 * @UpdateDate:
 * @Description:
 */
public abstract class StandardSqlProvider<JavaType, ColMark extends Annotation>
        extends AbstractSqlProviderFrame<JavaType,ColMark>
        implements BaseSqlProvider<JavaType>, FieldRowsSqlProvider<JavaType> {

    protected StandardSqlProvider(Class<JavaType> javaType,
                                  Class<ColMark> colMark){
        super(javaType,colMark);
    }

    public StandardSqlProvider(){
        super();
    }

    /*========================= INSERT ================================*/
    @Override
    public final String insert(@NotNull JavaType inst) throws Throwable {
        return Insert._chooseInsert(inst,false,this);
    }

    @Override
    public String insertMulti(@NotNull List<JavaType> instMulti) throws Throwable {
        SureOF.notEmptyList(instMulti, "The multiply instances for insert cont't be null.");
        return Insert._chooseInsertMulti(instMulti,false,this);
    }

    @Override
    public final String insertSmart(@NotNull JavaType inst) throws Throwable {
        return Insert._chooseInsert(inst,true,this);
    }

    @Override
    public String insertSmartMulti(List<JavaType> instMulti) throws Throwable {
        SureOF.notEmptyList(instMulti, "The multiply instances for insert cont't be null.");
        return Insert._chooseInsertMulti(instMulti,true,this);
    }

    /*========================= UPDATE ================================*/
    @Override
    public final String updateByPrimary(@NotNull JavaType inst) throws Throwable {
        return Update._chooseUpdateByPrimary(inst,false,this);
    }

    @Override
    public final String updateSmartByPrimary(@NotNull JavaType inst) throws Throwable {
        return Update._chooseUpdateByPrimary(inst,true,this);
    }

    @Override
    public String updateByConsult(@NotNull JavaType inst,@NotNull Consult<JavaType> consult) throws Throwable {
        SureOF.equals(this.javaType.isAssignableFrom(consult.javaType), Boolean.TRUE,
                "The Consult lookup JavaType required fit to SqlProvider frame.");
        return Update._chooseUpdateByConsult(inst, consult,false,this);
    }

    @Override
    public String updateSmartByConsult(@NotNull JavaType inst, @NotNull Consult<JavaType> consult) throws Throwable {
        SureOF.equals(this.javaType.isAssignableFrom(consult.javaType), Boolean.TRUE,
                "The Consult lookup JavaType required fit to SqlProvider frame.");
        return Update._chooseUpdateByConsult(inst, consult,true,this);
    }

    /*========================= DELETE ================================*/
    @Override
    public final String deleteByPrimary(@NotNull JavaType inst) throws Throwable {
        return Delete._deleteByPrimary(inst,this);
    }

    @Override
    public String deleteSmart(@NotNull JavaType inst) throws Throwable {
        return Delete._chooseDelete(inst,false,this);
    }

    @Override
    public String deleteByConsult(@NotNull Consult<JavaType> consult) throws Throwable {
        SureOF.equals(this.javaType.isAssignableFrom(consult.javaType), Boolean.TRUE,
                "The Consult lookup JavaType required fit to SqlProvider frame.");
        return Delete._deleteByConsult(consult,false,this);
    }

    /*========================= SELECT ================================*/
    @Override
    public String queryAll() throws Throwable {
        return Query._queryAll(this);
    }

    @Override
    public String queryByPrimary(@NotNull JavaType inst) throws Throwable {
        return Query._queryByPrimary(inst,this);
    }

    @Override
    public String querySmart(@NotNull JavaType inst) throws Throwable {
        return Query._chooseQuery(inst,this);
    }

    @Override
    public String queryByConsult(@NotNull Consult<JavaType> consult) throws Throwable {
        SureOF.equals(this.javaType.isAssignableFrom(consult.javaType), Boolean.TRUE,
                "The Consult lookup JavaType required fit to SqlProvider frame.");
        return Query._queryByConsult(consult,this);
    }

    /*=========================== SAVE =============================*/
    @Override
    public String save(@NotNull JavaType inst, @NotNull SaveMode saveMode) throws Throwable {
        return saveMulti(Arrays.asList(inst),saveMode);
    }

    @Override
    public String saveMulti(@NotNull List<JavaType> instMulti, @NotNull SaveMode saveMode) throws Throwable {
        SureOF.notEmptyList(instMulti, "The multiply instances for save cont't be null.");
        SureOF.notNull(saveMode, "The saveMode is necessary.");
        return Save._chooseSaveMulti(instMulti,saveMode,false,this);
    }

    @Override
    public String saveSmart(@NotNull JavaType inst, @NotNull SaveMode saveMode) throws Throwable {
        return saveSmartMulti(Arrays.asList(inst),saveMode);
    }

    @Override
    public String saveSmartMulti(@NotNull List<JavaType> instMulti, @NotNull SaveMode saveMode) throws Throwable {
        SureOF.notEmptyList(instMulti, "The multiply instances for save cont't be null.");
        SureOF.notNull(saveMode, "The saveMode is necessary.");
        return Save._chooseSaveMulti(instMulti,saveMode,true,this);
    }

    /*=========================== COUNT =============================*/
    @Override
    public String countAll() throws Throwable {
        return Count._countAll(this);
    }

    @Override
    public String countSmart(@NotNull JavaType inst) throws Throwable {
        return Count._chooseCount(inst, this);
    }

    @Override
    public String countByConsult(@NotNull Consult<JavaType> consult) throws Throwable {
        return Count._countByConsult(consult, this);
    }

    /*=========================== FIELD ROWS =============================*/
    @Override
    public String fieldRow(FieldsTouch<JavaType, ?> touch) throws Throwable {
        return FieldRows._fieldRowsLimit(touch, true, this);
    }

    @Override
    public String fieldRows(FieldsTouch<JavaType, ?> touch) throws Throwable {
        return FieldRows._fieldRowsLimit(touch, false, this);
    }

    @Override
    public String fieldRowSmart(JavaType inst, FieldsTouch<JavaType, ?> touch) throws Throwable {
        return FieldRows._fieldRowsSmartLimit(inst, touch, true, this);
    }

    @Override
    public String fieldRowsSmart(JavaType inst, FieldsTouch<JavaType, ?> touch) throws Throwable {
        return FieldRows._fieldRowsSmartLimit(inst, touch, false, this);
    }

    @Override
    public String fieldRowByConsult(Consult<JavaType> consult, FieldsTouch<JavaType, ?> touch) throws Throwable {
        return FieldRows._fieldRowsByConsultLimit(consult, touch, true, this);
    }

    @Override
    public String fieldRowsByConsult(Consult<JavaType> consult, FieldsTouch<JavaType, ?> touch) throws Throwable {
        return FieldRows._fieldRowsByConsultLimit(consult, touch, false, this);
    }
}
